Skip to content

nginx: a missing certificate no longer stops the server - #14

Merged
zelti merged 2 commits into
mainfrom
fix/nginx-cert-fallback
Aug 24, 2026
Merged

zelti merged 2 commits into
mainfrom
fix/nginx-cert-fallback

Conversation

@zelti

@zelti zelti commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Found while verifying task 38 against a local stack. Without certificates/php-devforge.pem — a fresh clone, or one where install_cert.sh was skipped — nginx refuses to start and the container restarts forever:

nginx: [emerg] cannot load certificate "/etc/nginx/ssl/php-devforge.pem"

Apache in the same state generates a self-signed certificate and serves with a browser warning. Task 7 gave it that safety net; nginx never got one. Since #10 made forge profile on nginx a documented command, this is a state people will reach.

The fix

nginx has no equivalent of Apache's <IfFile>, so the choice is made in an entrypoint and handed to the template as $SSL_CERT / $SSL_KEY. The templates were already rendered with envsubst, so this adds two names to a variable list that exists precisely to keep nginx's own $mail and $subdomains from being substituted.

The entrypoint also absorbed the envsubst calls that were inlined in CMD, which is now just ["openresty", "-g", "daemon off;"] — the same shape as the Apache image.

Kept as a second copy rather than shared with Apache's: the common part is twelve lines of openssl, and sharing it means widening both build contexts from ./docker-library/{httpd,nginx} to ./docker-library, shipping every other image's files as context.

Planning turned up a second hole

Apache's fallback had never been tested either. Nothing in CI removed the certificates — install_cert.sh runs first, so one always existed. The net written in task 7 had been assumed to work for weeks. It does, verified here for the first time, but that is luck rather than coverage.

The new step exercises both servers, and checks the certificate's issuer rather than trusting curl -k, which accepts anything — an assertion built on it would pass even if no fallback were generated and a stale file were being served. A self-signed certificate has issuer equal to subject; mkcert's does not.

Proven, not assumed

the step fails without the fix reverted the entrypoint, rebuilt, got nginxdev is not running
the cleanup survives a failure the first version left the certificates aside when it died halfway, so every later step tested a degraded stack. A trap ... EXIT now restores them — verified by making it fail on purpose

zelti added 2 commits August 23, 2026 23:00
Without certificates/php-devforge.pem nginx refused to start and the
container restarted forever, while Apache in the same state generated a
self-signed certificate and served with a browser warning. Since task 38
made 'forge profile on nginx' a documented command, that is a state
people will reach.

nginx has no <IfFile>, so an entrypoint picks the certificate and hands
it to the template as $SSL_CERT / $SSL_KEY. It also absorbed the
envsubst calls inlined in CMD, which is now just openresty.

Kept separate from Apache's copy on purpose: sharing twelve lines of
openssl would mean widening both build contexts to ./docker-library.

Planning turned up a second hole -- Apache's fallback had never been
tested either, because CI always runs install_cert.sh first. The new
step covers both, and checks the certificate's issuer rather than
trusting 'curl -k', which accepts anything.

Verified the step fails with the fix reverted, and that its trap puts
the certificates back when it dies halfway.
The check grepped the issuer for 'CN=phpforge.dev'. The runner's OpenSSL
prints 'CN = phpforge.dev' with spaces, this machine's does not, so it
failed on GitHub after passing locally.

It now compares issuer to subject. That is what self-signed means, and it
does not depend on how a particular build formats a name.
@zelti
zelti merged commit 5df65f6 into main Aug 24, 2026
4 checks passed
@zelti
zelti deleted the fix/nginx-cert-fallback branch August 24, 2026 03:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant